/**
 * ReportGear(2011)
 */
package net.abbp.report.model;

import java.awt.Rectangle;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.swing.JOptionPane;

import org.dom4j.Element;

import net.abbp.core.transform.xml.jaxb.ColorAdapter;
import net.abbp.core.util.BooleanUtils;
import net.abbp.core.util.NumberUtils;
import net.abbp.core.util.StringUtils;
import net.abbp.report.model.cell.style.BorderStyle;
import net.abbp.report.model.cell.style.FontStyle;
import net.abbp.report.model.cell.style.HorizentalAlignment;
import net.abbp.report.model.cell.style.Style;
import net.abbp.report.model.cell.style.TextStyle;
import net.abbp.report.model.cell.style.VerticalAlignment;
import net.abbp.report.model.io.IValueIO;
import net.abbp.report.model.io.ValueIOManager;
import net.abbp.report.utils.ColorUtils;
import net.abbp.report.view.GridView;

import com.reportgear.core.api.BaseObject;
import com.reportgear.report.model.auxiliary.ColumnPropList;
import com.reportgear.report.model.auxiliary.ColumnProperty;
import com.reportgear.report.model.auxiliary.ColumnRow;
import com.reportgear.report.model.auxiliary.ColumnType;
import com.reportgear.report.model.auxiliary.RowPropList;
import com.reportgear.report.model.auxiliary.RowProperty;
import com.reportgear.report.model.auxiliary.RowType;
import com.reportgear.report.parameter.model.Parameter;
import com.reportgear.report.setting.ReportSettings;
import com.reportgear.report.view.grid.selection.Selection;

/**
 * 报表模型
 * 
 * @version 1.0 2011-3-11
 * @author <a herf="lexloo@gmail.com">lexloo</a>
 * @since abbp 1.0
 */
public class ReportModel extends BaseObject {
    /**
     * 默认空对象
     */
    public static final ReportModel EMPTY_MODEL = new ReportModel();
    /**
     * 模型版本
     */
    private String version = "1.0";
    // 模型的基本信息，针对不同类型的模型，包含一个不同类型的信息类
    private InfoObject infoObject;
    // 列属性列表
    private ColumnPropList columnPropList = new ColumnPropList();
    // 行属性列表
    private RowPropList rowPropList = new RowPropList();;
    // 报表配置
    private ReportSettings reportSettings = new ReportSettings();;
    // 模型参数
    private List<Parameter> parameters = new ArrayList<Parameter>();;
    // 单元格容器
    private CellGrid cellGrid = new CellGrid();

    // 属性改变事件支持
    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
    private transient Object objectLock = new Object();

    /**
     * 构造函数
     */
    public ReportModel() {}

    private Object getObjectLock() {
        return objectLock;
    }

    /**
     * 添加属性改变监听器
     * 
     * @param listener 监听器
     */
    public void addPropertyChangeListener(PropertyChangeListener listener) {
        synchronized (getObjectLock()) {
            if (listener == null) {
                return;
            }
            if (changeSupport == null) {
                changeSupport = new PropertyChangeSupport(this);
            }
            changeSupport.addPropertyChangeListener(listener);
        }
    }

    /**
     * 移除属性改变监听器
     * 
     * @param listener 监听器
     */
    public void removePropertyChangeListener(PropertyChangeListener listener) {
        synchronized (getObjectLock()) {
            if ((listener == null) || (changeSupport == null)) {
                return;
            }
            changeSupport.removePropertyChangeListener(listener);
        }
    }

    /**
     * 添加属性改变监听器
     * 
     * @param propertyName 属性名
     * @param listener 监听器
     */
    public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        synchronized (getObjectLock()) {
            if (listener == null) {
                return;
            }
            if (changeSupport == null) {
                changeSupport = new PropertyChangeSupport(this);
            }
            changeSupport.addPropertyChangeListener(propertyName, listener);
        }
    }

    /**
     * 移除属性改变监听器
     * 
     * @param propertyName 属性名
     * @param listener 监听器
     */
    public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
        synchronized (getObjectLock()) {
            if ((listener == null) || (changeSupport == null)) {
                return;
            }
            changeSupport.removePropertyChangeListener(propertyName, listener);
        }
    }

    /**
     * 触发属性改变
     * 
     * @param propertyName 属性值
     * @param oldValue 旧值
     * @param newValue 新值
     */
    public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
        PropertyChangeSupport changeSupport;
        synchronized (getObjectLock()) {
            changeSupport = this.changeSupport;
        }
        if ((changeSupport == null) || ((oldValue != null) && (newValue != null) && oldValue.equals(newValue))) {
            return;
        }
        changeSupport.firePropertyChange(propertyName, oldValue, newValue);
    }

    /**
     * 获取列属性列表
     * 
     * @return 列属性列表
     */
    public ColumnPropList getColumnPropList() {
        return this.columnPropList;
    }

    /**
     * 获取行属性列表
     * 
     * @return 行属性列表
     */
    public RowPropList getRowPropList() {
        return this.rowPropList;
    }

    /**
     * 获取Cell像素范围
     * 
     * @param worksheet 工作薄
     * @param cell 单元格
     * @return Cell像素范围
     */
    public Rectangle getCellRectangle(GridView worksheet, Cell cell) {
        return this.getCellRectangle(worksheet,
                                     cell.getColumn(),
                                     cell.getRow(),
                                     cell.getColumnSpan(),
                                     cell.getRowSpan());
    }

    /**
     * 获取Cell像素范围
     * 
     * @param worksheet 工作薄
     * @param selection 选择集
     * @return Cell像素范围
     */
    public Rectangle getCellRectangle(GridView worksheet, Selection selection) {
        return this.getCellRectangle(worksheet,
                                     selection.getColumn(),
                                     selection.getRow(),
                                     selection.getColumSpan(),
                                     selection.getRowSpan());
    }

    /**
     * 获取Cell像素范围
     * 
     * @param column Cell所在列
     * @param row Cell所在行
     * @param columnSpan Cell列跨度
     * @param rowSpan Cell行跨度
     * @return Cell像素范围
     */
    public Rectangle getCellRectangle(GridView worksheet, int column, int row, int columnSpan, int rowSpan) {
        int x = this.columnPropList.getRangeValue(worksheet.getHoriBeginValue(), column);
        int y = this.rowPropList.getRangeValue(worksheet.getVertBeginValue(), row);

        int w = 0;
        for (int i = 0; i < columnSpan; i++) {
            w += this.columnPropList.getWidth(column + i);
        }

        int h = 0;
        for (int j = 0; j < rowSpan; j++) {
            h += this.rowPropList.getHeight(row + j);
        }

        return new Rectangle(x, y, w, h);
    }

    /**
     * 添加单元格
     * 
     * @param cell 单元格
     */
    public void addCell(Cell cell) {
        // int oldColumnCount = this.getColumnCount();
        // int oldRowCount = this.getRowCount();
        this.cellGrid.add(cell);

        // this.firePropertyChange("ColumnCount", oldColumnCount, this.getColumnCount());
        // this.firePropertyChange("RowCount", oldRowCount, this.getRowCount());
    }

    /**
     * 移除单元格
     * 
     * @param cell 单元格
     */
    public void removeCell(Cell cell) {
        int oldColumnCount = this.getColumnCount();
        int oldRowCount = this.getRowCount();

        this.cellGrid.remove(cell);

        this.firePropertyChange("ColumnCount", oldColumnCount, this.getColumnCount());
        this.firePropertyChange("RowCount", oldRowCount, this.getRowCount());
    }

    /**
     * 添加列
     * 
     * @param index 列索引
     */
    public void addColumn(int index) {
        if (this.hasMergedColumnCells(index)) {
            return;
        }

        int oldColumnCount = this.getColumnCount();
        this.columnPropList.add(index, new ColumnProperty());
        this.cellGrid.addColumn(index);

        this.firePropertyChange("ColumnCount", oldColumnCount, this.getColumnCount());
    }

    /**
     * 查找所在列是否包含合并单元格
     * 
     * @param index 列序号
     * @return 包含情况
     */
    private boolean hasMergedColumnCells(int index) {
        for (int i = 0, count = this.getRowCount(); i < count; i++) {
            Cell c = this.getCell(index, i);
            if (c == Cell.EMPTY_CELL || c.isMerged()) {
                JOptionPane.showMessageDialog(null, "包含合并单元格", "错误", JOptionPane.WARNING_MESSAGE);
                return true;
            }
        }

        return false;
    }

    /**
     * 添加行
     * 
     * @param index 行索引
     */
    public void addRow(int index) {
        int oldRowCount = this.getRowCount();
        if (this.hasMergedRowCells(index)) {
            return;

        }

        this.rowPropList.add(index, new RowProperty());
        this.cellGrid.addRow(index);

        this.firePropertyChange("RowCount", oldRowCount, this.getRowCount());
    }

    /**
     * 查找所在行是否包含合并单元格
     * 
     * @param index 行序号
     * @return 包含情况
     */
    private boolean hasMergedRowCells(int index) {
        for (int i = 0, count = this.getColumnCount(); i < count; i++) {
            Cell c = this.getCell(i, index);
            if (c == Cell.EMPTY_CELL || c.isMerged()) {
                JOptionPane.showMessageDialog(null, "包含合并单元格", "错误", JOptionPane.WARNING_MESSAGE);
                return true;
            }
        }

        return false;
    }

    /**
     * 移除列
     * 
     * @param index 列索引(0 基)
     */
    public void removeColumn(int index) {
        int oldColumnCount = this.getColumnCount();
        if (this.hasMergedColumnCells(index)) {
            return;

        }

        this.columnPropList.remove(index);
        this.cellGrid.deleteColumn(index);

        this.firePropertyChange("ColumnCount", oldColumnCount, this.getColumnCount());
    }

    /**
     * 移除行
     * 
     * @param index 行索引(0 基)
     */
    public void removeRow(int index) {
        int oldRowCount = this.getRowCount();
        if (this.hasMergedRowCells(index)) {
            return;
        }

        this.rowPropList.remove(index);
        this.cellGrid.deleteRow(index);

        this.firePropertyChange("RowCount", oldRowCount, this.getRowCount());
    }

    /**
     * 获取指定单元格
     * 
     * @param column 行
     * @param row 列
     * @return 单元格
     */
    public Cell getCell(int column, int row) {
        return this.cellGrid.getCell(column, row);
    }

    /**
     * 获取指定单元格
     * 
     * @param sel 区域
     * @return 单元格
     */
    public Cell getCell(Selection sel) {
        return this.getCell(sel.getColumn(), sel.getRow());
    }

    /**
     * 获取列单元格迭代器
     * 
     * @param index 列索引
     * @return 列单元格迭代器
     */
    public Iterator<Cell> getColumn(int index) {
        return this.cellGrid.getColumn(index);
    }

    /**
     * 获取所有单元格迭代器
     * 
     * @return 单元格迭代器
     */
    public Iterator<Cell> getCellIterator() {
        return this.cellGrid.cellIterator();
    }

    /**
     * 获取包含指定对象类的Cell迭代器
     * 
     * @param clazz 指定对象类
     * @return 迭代器
     */
    public Iterator<Cell> getCellsIteratorByCellElementClass(Class<?> clazz) {
        return this.cellGrid.getCellsByElementClass(clazz);
    }

    /**
     * 获取行单元格索引
     * 
     * @param index 行索引
     * @return 行单元格索引
     */
    public Iterator<Cell> getRow(int index) {
        return this.cellGrid.getRow(index);
    }

    /**
     * 
     * Cell交叉集
     * 
     * @param columnFrom 开始行 0 based
     * @param rowFrom 开始列 0 based
     * @param columnTo 列跨度
     * @param rowTo 行跨度
     * @return 迭代器
     */
    public Iterator<Cell> intersect(int columnFrom, int rowFrom, int columnTo, int rowTo) {
        return this.cellGrid.intersect(columnFrom, rowFrom, columnTo, rowTo);
    }

    /**
     * 获取列宽度
     * 
     * @param index 列索引
     * @return 列宽度
     */
    public int getColumnWidth(int index) {
        return this.columnPropList.getWidth(index);
    }

    /**
     * 设置列宽度
     * 
     * @param index 列索引
     * @param width 列宽度
     */
    public void setColumnWidth(int index, int width) {
        this.columnPropList.setWidth(index, width);
    }

    /**
     * 获取单元格总宽度
     * 
     * @return 单元格总宽度
     */
    public int getTotalCellWeight() {
        return this.columnPropList.getRangeValueFromZero(this.getColumnCount());
    }

    /**
     * 获取列类型
     * 
     * @param index 列索引
     * @return 列类型
     */
    public ColumnType getColumnType(int index) {
        return this.columnPropList.getType(index);
    }

    /**
     * 设置列类型
     * 
     * @param index 列索引
     * @param columnType 列类型
     */
    public void setColumnType(int index, ColumnType columnType) {
        this.columnPropList.setType(index, columnType);
    }

    /**
     * 获取行高度
     * 
     * @param index 行索引
     * @return 行高度
     */
    public int getRowHeight(int index) {
        return this.rowPropList.getHeight(index);
    }

    /**
     * 设置行高度
     * 
     * @param index 行索引
     * @param height 行高度
     */
    public void setRowHeight(int index, int height) {
        this.rowPropList.setHeight(index, height);
    }

    /**
     * 获取单元格总高度
     * 
     * @return 单元格总高度
     */
    public int getTotalCellHeight() {
        return this.rowPropList.getRangeValueFromZero(this.getRowCount());
    }

    /**
     * 获取行类型
     * 
     * @param index 行索引
     * @return 行类型
     */
    public RowType getRowType(int index) {
        return this.rowPropList.getType(index);
    }

    /**
     * 设置行类型
     * 
     * @param index 索引
     * @param rowType 行类型
     */
    public void setRowType(int index, RowType rowType) {
        this.rowPropList.setType(index, rowType);
    }

    /**
     * 合并单元格
     * 
     * @param column 列
     * 
     * @param row 行
     * @param columnSpan 列跨度
     * @param rowSpan 行跨度
     */
    public void mergeCell(int column, int row, int columnSpan, int rowSpan) {
        Cell cell = this.cellGrid.getCell(column, row);

        List<Cell> forRemove = new ArrayList<Cell>();
        Iterator<Cell> itr = this.cellGrid.intersect(column, row, columnSpan, rowSpan);
        while (itr.hasNext()) {
            Cell c = itr.next();
            if (c != cell) {
                forRemove.add(c);
            }
        }

        // 必须要一起删除，应为迭代器中使用了cellGrid的size
        for (Cell c : forRemove) {
            this.cellGrid.remove(c);
        }

        if (cell == Cell.EMPTY_CELL) {
            cell = new Cell(column, row);
        }

        cell.setColumnSpan(columnSpan);
        cell.setRowSpan(rowSpan);
        this.addCell(cell);
    }

    /**
     * 取消单元格合并
     * 
     * @param column 列
     * @param row 行
     * @param columnSpan 列跨度
     * @param rowSpan 行跨度
     */
    public void unmergeCell(int column, int row, int columnSpan, int rowSpan) {
        Iterator<Cell> iterator = this.cellGrid.intersect(column, row, columnSpan, rowSpan);

        while (iterator.hasNext()) {
            Cell c = iterator.next();
            this.unmergeCell(c);
        }
    }

    /**
     * 取消单元格合并
     * 
     * @param cell 单元格
     */
    private void unmergeCell(Cell cell) {
        cell.setColumnSpan(1);
        cell.setRowSpan(1);
    }

    /**
     * 设置单元格的值
     * 
     * @param column 列
     * @param row 行
     * @param value 值
     */
    public void setCellValue(int column, int row, Object value) {
        // TODO 改成事件提示,判断要处理,有可能是合并单元格
        int rowCount = this.getRowCount();
        int tempCount = row + 1;

        this.cellGrid.setCellValue(column, row, value);

        if (tempCount > rowCount) {
            // 是扩展的新行,复制高度
            this.setRowHeight(row, this.getRowHeight(row - 1));
        }
    }

    /**
     * 增加对象到指定的矩形框中的所有单元格
     * 
     * @param value 要加入的单元格对象
     * @param sel 选择范围
     */
    public void setCellValue(Selection sel, Object value) {
        int column = sel.getColumn();
        int row = sel.getRow();

        for (int i = 0, lenX = sel.getColumSpan(); i < lenX; i++) {
            for (int j = 0, lenY = sel.getRowSpan(); j < lenY; j++) {
                this.setCellValue(column, row, value);
            }
        }
    }

    /**
     * 获取合并到的单元格
     * 
     * @param column 列
     * @param row 行
     * @return 单元格
     */
    public Cell getMergedToCell(int column, int row) {
        for (Cell c : this.cellGrid.cells) {
            if (c.isInCell(column, row)) {
                return c;
            }
        }

        return Cell.EMPTY_CELL;
    }

    /**
     * 获取单元格的浮点值
     * 
     * @param column 行
     * @param row 列
     * @return 单元格浮点值
     */
    public double getCellDoubleValue(int column, int row) {
        Cell cell = this.getCell(column, row);

        if (cell != null) {
            Object element = cell.getValue();

            if (element != null) {
                return NumberUtils.convertToDouble(element, 0.0D);
            }
        }

        return 0.0D;
    }

    /**
     * 获取单元格的值
     * 
     * @param cr ColumnRow对象
     * @return 单元格浮点值
     */
    public double getCellDoubleValue(ColumnRow cr) {
        return this.getCellDoubleValue(cr.getColumn(), cr.getRow());
    }

    /**
     * @return 列总数
     */
    public int getColumnCount() {
        return this.cellGrid.getColumnCount();
    }

    /**
     * @return 行总数
     */
    public int getRowCount() {
        return this.cellGrid.getRowCount();
    }

    /**
     * 报表设置
     * 
     * @param reportSettings 报表设置
     */
    public void setReportSettings(ReportSettings reportSettings) {
        this.reportSettings = reportSettings;
    }

    /**
     * 获取报表设置
     * 
     * @return 报表设置
     */
    public ReportSettings getReportSettings() {
        return reportSettings;
    }

    /**
     * 添加参数
     * 
     * @param parameter 参数对象
     */
    public void addParameter(Parameter parameter) {
        this.parameters.add(parameter);
    }

    /**
     * 获取模型参数列表
     * 
     * @return 参数列表
     */
    public List<Parameter> getParameters() {
        return this.parameters;
    }

    /**
     * 根据参数名称获取参数值
     * 
     * @param name 参数名称
     * @return 参数值
     */
    public Object getParameter(String name) {
        if (!StringUtils.isEmpty(name)) {
            for (Parameter para : this.parameters) {
                if (name.equals(para.getName())) {
                    return para.getObject();
                }
            }
        }

        return "";
    }

    /**
     * 
     * @return 获取固定列首
     */
    public List<Integer> getFixedHeaderColumns() {
        return getColumnsByType(ColumnType.HEADER);
    }

    /**
     * 
     * @return 获取固定列尾
     */
    public List<Integer> getFixedFooterColumns() {
        return getColumnsByType(ColumnType.FOOTER);
    }

    /**
     * 获取指定类型的列
     * 
     * @param type 指定类型
     * @return 列索引列表
     */
    private List<Integer> getColumnsByType(ColumnType type) {
        List<Integer> result = new ArrayList<Integer>();

        for (int i = 0, size = this.getColumnCount(); i < size; i++) {
            ColumnProperty p = this.columnPropList.get(i);

            if (p.getType() == type) {
                result.add(i);
            }
        }

        return result;
    }

    /**
     * 是否固定列
     * 
     * @param column 指定列
     * @return 是否固定列
     */
    public boolean isFixedColumn(int column) {
        ColumnProperty p = this.columnPropList.get(column);

        return (p.getType() == ColumnType.HEADER) || (p.getType() == ColumnType.FOOTER);
    }

    /**
     * 
     * @return 获取固定行首
     */
    public List<Integer> getFixedHeaderRows() {
        return getFixedRowsByType(RowType.HEADER);
    }

    /**
     * 
     * @return 获取固定行尾部
     */
    public List<Integer> getFixedFooterRows() {
        return getFixedRowsByType(RowType.FOOTER);
    }

    /**
     * 获取指定类型的行
     * 
     * @param type 指定类型
     * @return 行索引列表
     */
    private List<Integer> getFixedRowsByType(RowType type) {
        List<Integer> result = new ArrayList<Integer>();

        for (int i = 0, size = this.getRowCount(); i < size; i++) {
            RowProperty p = this.rowPropList.get(i);

            if (p.getType() == type) {
                result.add(i);
            }
        }

        return result;
    }

    /**
     * 是否固定行
     * 
     * @param row 指定行
     * @return 是否固定行
     */
    public boolean isFixedRow(int row) {
        RowProperty p = this.rowPropList.get(row);

        return (p.getType() == RowType.HEADER) || (p.getType() == RowType.FOOTER);
    }

    /**
     * 报表模型克隆
     * 
     * @return 报表模型
     */
    @Override
    public ReportModel clone() {
        ReportModel model = (ReportModel) super.clone();
        model.columnPropList = this.columnPropList.clone();
        model.rowPropList = this.rowPropList.clone();
        model.cellGrid = this.cellGrid.clone();

        return model;
    }

    /**
     * 复制行属性
     * 
     * @param dst 目标行索引
     * @param src 源行索引
     */
    public void copyRowProperties(int dst, int src) {
        // 复制高度
        this.setRowHeight(dst, this.getRowHeight(src));
        // 复制行属性
        this.setRowType(dst, this.getRowType(src));
        // 复制样式
        for (int i = 0, size = this.getColumnCount(); i < size; i++) {
            this.getCell(i, dst).setStyle(this.getCell(i, src).getStyle());
        }
    }

    /**
     * 获取报表模型的版本
     * 
     * @return 报表模型的版本
     */
    public String getVersion() {
        return version;
    }

    /**
     * 设置信息对象
     * 
     * @param infoObject 信息对象
     */
    public void setInfoObject(InfoObject infoObject) {
        this.infoObject = infoObject;
    }

    /**
     * 获取信息对象
     * 
     * @return 信息对象
     */
    public InfoObject getInfoObject() {
        return infoObject;
    }

    public static class IO implements IValueIO {

        @Override
        public Object read(Element value, ReportModel model) {
            Element elModel = value.element("ReportModel");
            String version = elModel.attributeValue("Version");
            ReportModel subModel = new ReportModel();
            if (subModel.getVersion() != version) {
                // 版本不对
            }

            this.readCPL(elModel, subModel);
            this.readRPL(elModel, subModel);
            Map<String, Style> stylesMap = this.readStyle(elModel);
            this.readCells(elModel, stylesMap, subModel);

            return subModel;
        }

        @Override
        public void write(Element element, Object value) {
            ReportModel rm = (ReportModel) value;
            Element model = element.addElement("ReportModel");
            model.addAttribute("Version", rm.getVersion());

            Map<Style, String> styleMap = this.createStyleMap(rm);

            this.createStyles(model, styleMap);
            this.createCPL(model, rm.getColumnPropList());
            this.createRPL(model, rm.getRowPropList());
            this.createCells(model, rm.getCellIterator(), styleMap);
        }

        /**
         * 创建样式
         * 
         * @param root 根节点
         * @param styleMap 样式Map
         */
        private void createStyles(Element root, Map<Style, String> styleMap) {
            Element elStyles = root.addElement("Styles");

            for (Map.Entry<Style, String> entry : styleMap.entrySet()) {
                Element elStyle = elStyles.addElement("Style");
                elStyle.addAttribute("Name", entry.getValue());

                Style style = entry.getKey();
                elStyle.addElement("TextStyle").addText(style.getTextStyle().name());
                elStyle.addElement("HorizentalAlignment").addText(style.getHorizentalAlignment().name());
                elStyle.addElement("VerticalAlignment").addText(style.getVerticalAlignment().name());

                Element elBorder = elStyle.addElement("BorderStyle");
                BorderStyle borderStyle = style.getBorderStyle();
                elBorder.addAttribute("BottomColor", ColorUtils.toHexEncoding(borderStyle.getBottomColor()));
                elBorder.addAttribute("BottomStyle", StringUtils.convertToString(borderStyle.getBottomStyle()));
                elBorder.addAttribute("HoriColor", ColorUtils.toHexEncoding(borderStyle.getHorizentalColor()));
                elBorder.addAttribute("HoriStyle", StringUtils.convertToString(borderStyle.getHorizentalStyle()));
                elBorder.addAttribute("LeftColor", ColorUtils.toHexEncoding(borderStyle.getLeftColor()));
                elBorder.addAttribute("LeftStyle", StringUtils.convertToString(borderStyle.getLeftStyle()));
                elBorder.addAttribute("RightColor", ColorUtils.toHexEncoding(borderStyle.getRightColor()));
                elBorder.addAttribute("RightStyle", StringUtils.convertToString(borderStyle.getRightStyle()));
                elBorder.addAttribute("TopColor", ColorUtils.toHexEncoding(borderStyle.getTopColor()));
                elBorder.addAttribute("TopStyle", StringUtils.convertToString(borderStyle.getTopStyle()));
                elBorder.addAttribute("VertColor", ColorUtils.toHexEncoding(borderStyle.getVerticalColor()));
                elBorder.addAttribute("VertStyle", StringUtils.convertToString(borderStyle.getVerticalStyle()));

                Element elFont = elStyle.addElement("FontStyle");
                FontStyle fontStyle = style.getFontStyle();
                elFont.addAttribute("Name", fontStyle.getName());
                elFont.addAttribute("Style", StringUtils.convertToString(fontStyle.getStyle(), "0"));
                elFont.addAttribute("Size", StringUtils.convertToString(fontStyle.getSize(), "12"));
                elFont.addAttribute("Foreground", ColorAdapter.toHexEncoding(fontStyle.getForeground()));
                elFont.addAttribute("Shadow", StringUtils.convertToString(fontStyle.isShadow(), "false"));
                elFont.addAttribute("Strikethrough", StringUtils.convertToString(fontStyle.isStrikethrough(), "false"));
                elFont.addAttribute("Subscript", StringUtils.convertToString(fontStyle.isSubscript(), "false"));
                elFont.addAttribute("Superscript", StringUtils.convertToString(fontStyle.isSuperscript(), "false"));
                elFont.addAttribute("Underline", StringUtils.convertToString(fontStyle.getUnderline(), ""));

                Element elFormat = elStyle.addElement("Format").addText(style.getFormatterKey());
            }
        }

        /**
         * 创建所有的StyleMap，用于单元格保存样式
         * 
         * @param model 当前模型
         * @return Style 演示
         */
        private Map<Style, String> createStyleMap(ReportModel model) {
            Map<Style, String> rtn = new HashMap<Style, String>();

            // 直接从单元格获取，避免重复的样式
            int ptr = 1;
            for (Iterator<Cell> itr = model.getCellIterator(); itr.hasNext();) {
                Cell cell = itr.next();

                Style style = cell.getStyle();
                if (style != null) {
                    if (!rtn.containsKey(style)) {
                        rtn.put(style, "Style" + (ptr++));
                    }
                }
            }

            return rtn;
        }

        /**
         * 序列化列信息
         * 
         * @param root 根节点
         * @param columnPropList 模型列配置
         * @return 序列化节点
         */
        private void createCPL(Element root, ColumnPropList columnPropList) {
            Element rtn = root.addElement("CPL");

            for (ColumnProperty prop : columnPropList.getAllElements()) {
                Element el = rtn.addElement("Prop");

                el.addAttribute("Width", StringUtils.convertToString(prop.getWidth()));
                el.addAttribute("Visible", StringUtils.convertToString(prop.isVisible()));
                el.addAttribute("Group", StringUtils.convertToString(prop.isGroup()));
                el.addAttribute("Type", StringUtils.convertToString(prop.getType()));
            }
        }

        /**
         * 序列化列信息
         * 
         * @param root 根节点
         * @param rowPropList 模型行配置
         * @return 序列化节点
         */
        private void createRPL(Element root, RowPropList rowPropList) {
            Element rtn = root.addElement("RPL");

            for (RowProperty prop : rowPropList.getAllElements()) {
                Element el = rtn.addElement("Prop");

                el.addAttribute("Height", StringUtils.convertToString(prop.getHeight()));
                el.addAttribute("Visible", StringUtils.convertToString(prop.isVisible()));
                el.addAttribute("Group", StringUtils.convertToString(prop.isGroup()));
                el.addAttribute("Type", StringUtils.convertToString(prop.getType()));
            }
        }

        /**
         * 序列化所有单元格
         * 
         * @param root 根节点
         * @param cellIterator 所有单元格
         * @param styleMap 样式Map
         */
        private void createCells(Element root, Iterator<Cell> cellIterator, Map<Style, String> styleMap) {
            Element rtn = root.addElement("Cells");
            ValueIOManager ioManager = ValueIOManager.INSTANCE;

            for (Iterator<Cell> itr = cellIterator; itr.hasNext();) {
                Cell cell = itr.next();

                Element el = rtn.addElement("Cell");
                el.addAttribute("C", StringUtils.convertToString(cell.getColumn()));
                el.addAttribute("R", StringUtils.convertToString(cell.getRow()));
                el.addAttribute("CS", StringUtils.convertToString(cell.getColumnSpan()));
                el.addAttribute("RS", StringUtils.convertToString(cell.getRowSpan()));
                el.addAttribute("Style", styleMap.get(cell.getStyle()));

                // 输出对象
                Object value = cell.getValue();
                if (value != null) {
                    Element elValue = el.addElement("Value");
                    elValue.addAttribute("Clazz", value.getClass().getName());

                    IValueIO io = ioManager.getValueIO(value.getClass());
                    io.write(elValue, value);
                }
            }
        }

        /**
         * 读入所有单元格
         * 
         * @param root 根节点
         * @param stylesMap 样式查找
         * @param model 模型
         */
        @SuppressWarnings("unchecked")
        private void readCells(Element root, Map<String, Style> stylesMap, ReportModel model) {
            ValueIOManager ioManager = ValueIOManager.INSTANCE;

            Element el = root.element("Cells");
            List<Element> cells = el.elements("Cell");
            for (Element c : cells) {
                Cell cell =
                        new Cell(NumberUtils.convertToInteger(c.attributeValue("C")),
                                 NumberUtils.convertToInteger(c.attributeValue("R")));
                cell.setColumnSpan(NumberUtils.convertToInteger(c.attributeValue("CS")));
                cell.setRowSpan(NumberUtils.convertToInteger(c.attributeValue("RS")));
                cell.setStyle(stylesMap.get(c.attributeValue("Style")));

                Element elValue = c.element("Value");
                if (elValue != null) {
                    IValueIO io = ioManager.getValueIO(elValue.attributeValue("Clazz"));
                    cell.setValue(io.read(c.element("Value"), model));
                }

                model.addCell(cell);
            }
        }

        /**
         * 读入CPL
         * 
         * @param root 根节点
         * @param model 当前模型
         */
        @SuppressWarnings("unchecked")
        private void readCPL(Element root, ReportModel model) {
            Element el = root.element("CPL");
            if (el != null) {
                List<Element> props = el.elements("Prop");
                for (int i = 0, size = props.size(); i < size; i++) {
                    Element ele = props.get(i);
                    model.setColumnWidth(i, NumberUtils.convertToInteger(ele.attributeValue("Width"), 0));
                    model.setColumnType(i, Enum.valueOf(ColumnType.class, ele.attributeValue("Type")));
                }
            }
        }

        /**
         * 读入RPL
         * 
         * @param root 根节点
         * @param model 当前模型
         */
        @SuppressWarnings("unchecked")
        private void readRPL(Element root, ReportModel model) {
            Element el = root.element("RPL");
            if (el != null) {
                List<Element> props = el.elements("Prop");
                for (int i = 0, size = props.size(); i < size; i++) {
                    Element ele = props.get(i);
                    model.setRowHeight(i, NumberUtils.convertToInteger(ele.attributeValue("Height"), 0));
                    model.setRowType(i, Enum.valueOf(RowType.class, ele.attributeValue("Type")));
                }
            }
        }

        /**
         * 读取所有样式
         * 
         * @param root 所有样式
         */
        @SuppressWarnings("unchecked")
        private Map<String, Style> readStyle(Element root) {
            Map<String, Style> stylesMap = new HashMap<String, Style>();

            Element elStyles = root.element("Styles");
            List<Element> styles = elStyles.elements("Style");
            for (Element elStyle : styles) {
                Style style = Style.getInstance();
                TextStyle textStyle = Enum.valueOf(TextStyle.class, elStyle.elementText("TextStyle"));
                style = style.derivetTextStyle(textStyle);

                HorizentalAlignment hAlign =
                        Enum.valueOf(HorizentalAlignment.class, elStyle.elementText("HorizentalAlignment"));
                style = style.derivetHorizentalAlignment(hAlign);

                VerticalAlignment vAlign =
                        Enum.valueOf(VerticalAlignment.class, elStyle.elementText("VerticalAlignment"));
                style = style.derivetVerticalAlignment(vAlign);

                BorderStyle borderStyle = BorderStyle.getInstance();
                Element elBorderStyle = elStyle.element("BorderStyle");
                borderStyle =
                        borderStyle.applyBottomColor(ColorUtils.parseToColor(elBorderStyle.attributeValue("BottomColor")));
                borderStyle =
                        borderStyle.applyBottomStyle(NumberUtils.convertToInteger(elBorderStyle.attributeValue("BottomStyle"),
                                                                                  0));
                borderStyle =
                        borderStyle.applyHorizentalColor(ColorUtils.parseToColor(elBorderStyle.attributeValue("HoriColor")));
                borderStyle =
                        borderStyle.applyHorizentalStyle(NumberUtils.convertToInteger(elBorderStyle.attributeValue("HoriStyle"),
                                                                                      0));
                borderStyle =
                        borderStyle.applyLeftColor(ColorUtils.parseToColor(elBorderStyle.attributeValue("LeftColor")));
                borderStyle =
                        borderStyle.applyLeftStyle(NumberUtils.convertToInteger(elBorderStyle.attributeValue("LeftStyle"),
                                                                                0));
                borderStyle =
                        borderStyle.applyRightColor(ColorUtils.parseToColor(elBorderStyle.attributeValue("RightColor")));
                borderStyle =
                        borderStyle.applyRightStyle(NumberUtils.convertToInteger(elBorderStyle.attributeValue("RightStyle"),
                                                                                 0));
                borderStyle =
                        borderStyle.applyTopColor(ColorUtils.parseToColor(elBorderStyle.attributeValue("TopColor")));
                borderStyle =
                        borderStyle.applyTopStyle(NumberUtils.convertToInteger(elBorderStyle.attributeValue("TopStyle"),
                                                                               0));
                borderStyle =
                        borderStyle.applyVerticalColor(ColorUtils.parseToColor(elBorderStyle.attributeValue("VertColor")));
                borderStyle =
                        borderStyle.applyVerticalStyle(NumberUtils.convertToInteger(elBorderStyle.attributeValue("VertStyle"),
                                                                                    0));
                style = style.deriveBorder(borderStyle);

                Element elFontStyle = elStyle.element("FontStyle");
                FontStyle fontStyle = FontStyle.getInstance();
                fontStyle = fontStyle.applyName(elFontStyle.attributeValue("Name"));
                fontStyle = fontStyle.applyStyle(NumberUtils.convertToInteger(elFontStyle.attributeValue("Style"), 0));
                fontStyle = fontStyle.applySize(NumberUtils.convertToInteger(elFontStyle.attributeValue("Size"), 12));
                fontStyle =
                        fontStyle.applyForeground(ColorUtils.parseToColor(elFontStyle.attributeValue("Foreground")));
                fontStyle = fontStyle.applyShadow(BooleanUtils.parseString(elFontStyle.attributeValue("Shadow")));
                fontStyle =
                        fontStyle.applyStrikethrough(BooleanUtils.parseString(elFontStyle.attributeValue("Strikethrough")));
                fontStyle = fontStyle.applySubscript(BooleanUtils.parseString(elFontStyle.attributeValue("Subscript")));
                fontStyle =
                        fontStyle.applySuperscript(BooleanUtils.parseString(elFontStyle.attributeValue("Superscript")));
                fontStyle =
                        fontStyle.applyUnderline(NumberUtils.convertToInteger(elFontStyle.attributeValue("Underline"),
                                                                              0));

                style = style.deriveReportFont(fontStyle);
                style = style.deriveFormatterKey(elStyle.elementText("Format"));

                stylesMap.put(elStyle.attributeValue("Name"), style);
            }

            return stylesMap;
        }
    }

    /**
     * 清除所有列
     */
    public void clear() {
        for (int i = this.getRowCount() - 1; i >= 0; i--) {
            this.rowPropList.remove(i);
        }

        for (int i = this.getColumnCount() - 1; i >= 0; i--) {
            this.columnPropList.remove(i);
        }

        this.cellGrid.clear();
    }
}
